using System;
using System.Linq;
using BSpec.Specification;
using BSpec.Specs;
using NUnit.Framework;

namespace scenario_specs
{
    namespace with_scenario_of
    {
        public abstract class creating_a_scenario_from_a_test_fixture_type : SpecificationBase<Scenario>
        {
            protected override void setup_scenario()
            {
            }
        }

        public abstract class adding_contexts_to_a_scenario
            : creating_a_scenario_from_a_test_fixture_type
        {
        }
    }

    namespace given_a_type_that_contains_a_test_fixture
    {
        [TestFixture]
        public class when_creating_a_scenario : with_scenario_of.creating_a_scenario_from_a_test_fixture_type
        {
            protected override Scenario create_subject()
            {
                return Scenario.Create(this.GetType());
            }

            protected override void execute_scenario()
            {
                with_scenario_result(() => the_subject);
            }

            [Test]
            public void should_be_named_for_the_test_fixture_concern()
            {
                the_scenario_result<Scenario>().Name.should_equal("Creating a scenario from a test fixture type");
            }
        }
    }

    namespace given_a_type_that_does_not_contain_a_scenario
    {
        [TestFixture]
        public class when_creating_a_scenario : with_scenario_of.creating_a_scenario_from_a_test_fixture_type
        {
            protected override Scenario create_subject()
            {
                return Scenario.Create(typeof(string));
            }

            protected override void execute_scenario()
            {
                with_scenario_result(() => the_subject);
            }

            [Test]
            public void should_return_a_null_scenario()
            {
                the_scenario_result<Scenario>().should_be_instance_of<NullScenario>();
            }
        }
    }

    namespace given_a_scenario
    {
        [TestFixture]
        public class when_adding_a_context : with_scenario_of.adding_contexts_to_a_scenario
        {
            protected override Scenario create_subject()
            {
                return Scenario.Create(this.GetType());
            }

            protected override void execute_scenario()
            {
                the_subject.AddContextFor(this.GetType());
            }

            [Test]
            public void should_add_the_context_to_the_scenario()
            {
                the_subject.Contexts.should_not_be_empty();
            }

            [Test]
            public void should_add_a_behaviour_to_the_context()
            {
                the_subject.Contexts.First().Behaviours.should_not_be_empty();
            }
        }

        namespace given_a_scenario_contains_a_context
        {
            [TestFixture]
            public class when_adding_a_context_that_already_exists : with_scenario_of.adding_contexts_to_a_scenario
            {
                protected override Scenario create_subject()
                {
                    return Scenario.Create(this.GetType());
                }

                protected override void execute_scenario()
                {
                    the_subject.AddContextFor(this.GetType());
                    the_subject.AddContextFor(this.GetType());
                }

                [Test]
                public void should_not_add_duplicate_contexts()
                {
                    the_subject.Contexts.Length.should_equal(1);
                }
            }
        }
    }
}   